package com.hodgepodge.commons.exception;

import com.hodgepodge.commons.base.entity.Result;
import com.hodgepodge.commons.enums.ResultCodeEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * title GlobalExceptionHandler
 * projectName colorful-blog
 * desc 全局异常
 *
 * @author jiangjian
 * @date 2021/6/1 17:53
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 自定义Api异常
     *
     * @param e 异常参数
     * @return 异常结果
     * @author jiangjian
     * @date 2021-06-01
     */
    @ExceptionHandler(ApiException.class)
    public Result<Object> apiExceptionHandler(ApiException e) {
        return Result.result(e.getResult());
    }

    /**
     * (@Validated @Valid仅对于表单提交有效，对于以json格式提交将会失效)
     *
     * @param e 异常参数
     * @return 异常结果
     * @author jiangjian
     * @date 2021-06-01
     */
    @ExceptionHandler(BindException.class)
    public Result<Object> bindExceptionHandler(BindException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        String messages = StringUtils.join(fieldErrors.stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage).toArray(), ";");
        return Result.result(ResultCodeEnum.PARAM_VALID_ERROR.getCode(), messages, null);
    }

    /**
     * (@Validated @Valid 前端提交的方式为json格式有效，出现异常时会被该异常类处理)
     *
     * @param e 异常参数
     * @return 异常结果
     * @author jiangjian
     * @date 2021-06-02
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Object> argumentValidExceptionHandler(MethodArgumentNotValidException e) {
        Optional<ObjectError> optional = e.getBindingResult()
                .getAllErrors()
                .stream()
                .findFirst();
        return optional
                .map(objectError -> Result.result(ResultCodeEnum.PARAM_VALID_ERROR.getCode(), objectError.getDefaultMessage(), null))
                .orElseGet(() -> Result.result(ResultCodeEnum.PARAM_VALID_ERROR));
    }

    /**
     * (@NotBlank @NotNull @NotEmpty)
     *
     * @param e 异常参数
     * @return 异常结果
     * @author jiangjian
     * @date 2021-06-02
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public Result<Object> constraintExceptionHandler(ConstraintViolationException e) {
        List<String> msgList = new ArrayList<>();
        for (ConstraintViolation<?> constraintViolation : e.getConstraintViolations()) {
            msgList.add(constraintViolation.getMessage());
        }
        String messages = StringUtils.join(msgList.toArray(), ";");
        return Result.result(ResultCodeEnum.PARAM_VALID_ERROR.getCode(), messages, null);
    }
}
